package org.nanhill.commons.id;

import org.nanhill.commons.id.uuid.UUID;

/**
 * <p>
 * <code>IdentifierUtils</code> provides convenience methods for generating
 * identifiers using the identifier generators
 * </p>
 * 
 * <p>
 * This class maintains a static instance of each generator and uses this
 * instance to generate identifiers via its corresponding nextXxx() method.
 * </p>
 * 
 * <p>
 * When this class is loaded, static instances are initialized using the
 * currently configured <code>IdentifierGeneratorFactory.</code> If
 * initialization fails, the static instances will be <code>null</code> and
 * the static identifier generation methods will throw null pointer exceptions.
 * This will not happen unless a custom configuration is used and the specified
 * factory class fails to load.
 * </p>
 * 
 * @version 2006-12-28
 * @author xalinx at gmail dot com
 * 
 */
public final class IdentifierUtils {


	/**
	 * Static {@link IdentifierGeneratorFactory} used to create generator
	 * instances
	 */
	private static IdentifierGeneratorFactory factory = createFactory();

	/**
	 * <p>
	 * Singleton instance of the <code>LongIdentifierFactory</code>.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated.
	 * </p>
	 * 
	 * <p>
	 * The objects returned are:
	 * </p>
	 * <ul>
	 * <li>new Long(0L)</li>
	 * <li>new Long(1L)</li>
	 * <li>new Long(2L)</li>
	 * <li>...</li>
	 * </ul>
	 */
	public static final LongIdentifierGenerator LONG_IDENTIFIER_GENERATOR = createLongIdentifierGenerator();

	/**
	 * <p>
	 * Singleton instance of the <code>StringNumericIdentifierFactory</code>.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated.
	 * </p>
	 * 
	 * <p>
	 * The objects returned are:
	 * </p>
	 * <ul>
	 * <li>"0"</li>
	 * <li>"1"</li>
	 * <li>"2"</li>
	 * <li>...</li>
	 * </ul>
	 */
	public static final StringIdentifierGenerator STRING_NUMERIC_IDENTIFIER_GENERATOR = createNumericIdentifierGenerator();

	/**
	 * <p>
	 * Singleton instance of the
	 * <code>StringAlphanumericIdentifierFactory</code>.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated. However, the length is 15 in base-36, so thats a lot of
	 * identifiers.
	 * </p>
	 * 
	 * <p>
	 * The objects returned are:
	 * </p>
	 * <ul>
	 * <li>"000000000000001"</li>
	 * <li>"000000000000002"</li>
	 * <li>"000000000000003"</li>
	 * <li>...
	 * <li>"00000000000000y"</li>
	 * <li>"00000000000000z"</li>
	 * <li>"000000000000010"</li>
	 * <li>"000000000000011"</li>
	 * <li>...
	 * <li>"00000000000001z"</li>
	 * <li>"000000000000020"</li>
	 * <li>...</li>
	 * </ul>
	 */
	public static final StringIdentifierGenerator STRING_ALPHANUMERIC_IDENTIFIER_GENERATOR = createAlphanumericGenerator();

	/**
	 * <p>
	 * Singleton instance of the <code>StringSessionIdentifierFactory</code>.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance may produce duplicates in a long-lived server, but
	 * its unlikely.
	 * </p>
	 * 
	 * <p>
	 * The objects returned are 10 or more base-36 digits.
	 * </p>
	 */
	public static final StringIdentifierGenerator STRING_SESSION_IDENTIFIER_GENERATOR = createSessionIdGenerator();

	/**
	 * <p>
	 * Singleton instance of the uuid <code>VersionOneGenerator</code>.
	 * </p>
	 * 
	 * <p>
	 * Generates {@link org.apache.commons.id.uuid.UUID} Objects according to
	 * the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * </p>
	 * 
	 */
	public static final IdentifierGenerator<UUID> UUID_VERSION_ONE_GENERATOR = createUUIDVersionOneGenerator();

	/**
	 * <p>
	 * Singleton instance of the uuid <code>VersionFourGenerator</code>.
	 * </p>
	 * 
	 * <p>
	 * Generates {@link org.apache.commons.id.uuid.UUID} Objects according to
	 * the <a
	 * href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-02.txt">
	 * IETF Draft UUID specification</a>.
	 * </p>
	 * 
	 */
	public static final IdentifierGenerator<UUID> UUID_VERSION_FOUR_GENERATOR = createUUIDVersionFourGenerator();

	// ---------------------------------------------------------------------------------

	/**
	 * <p>
	 * Constructor.
	 * </p>
	 * 
	 */
	private IdentifierUtils() {
	}

	// ---------------------------------------------------------------------------------

	/**
	 * <p>
	 * Gets the next identifier using the singleton instance of the Long
	 * factory.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated.
	 * </p>
	 * 
	 * @return a new identifier
	 */
	public static long nextLongIdentifier() {
		return LONG_IDENTIFIER_GENERATOR.nextLongIdentifier();
	}

	// ---------------------------------------------------------------------------------

	/**
	 * <p>
	 * Gets the next identifier using the singleton instance of the String
	 * Alphanumeric factory.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated.
	 * </p>
	 * 
	 * @return a new identifier
	 */
	public static String nextStringAlphanumericIdentifier() {
		return STRING_ALPHANUMERIC_IDENTIFIER_GENERATOR.nextStringIdentifier();
	}

	public static UUID nextUUIDFourIdentifier() {
		return UUID_VERSION_FOUR_GENERATOR.nextIdentifier();
	}

	// ---------------------------------------------------------------------------------

	/**
	 * <p>
	 * Gets the next identifier using the singleton instance of the String
	 * Session factory.
	 * </p>
	 * 
	 * <p>
	 * The generation routine is based on a random number and a counter within a
	 * 2 second time interval.
	 * </p>
	 * 
	 * @return a new identifier
	 */
	public static String nextStringSessionIdentifier() {
		return STRING_SESSION_IDENTIFIER_GENERATOR.nextStringIdentifier();
	}

	/**
	 * <p>
	 * Gets the next identifier using the singleton instance of the String
	 * Numeric factory.
	 * </p>
	 * 
	 * <p>
	 * The singleton instance will wrap, so in a long-lived server, the id may
	 * be duplicated.
	 * </p>
	 * 
	 * @return a new identifier
	 */
	public static String nextStringNumericIdentifier() {
		return STRING_NUMERIC_IDENTIFIER_GENERATOR.nextStringIdentifier();
	}

	/**
	 * <p>
	 * Gets an IdentifierGeneratorFactory instance to use for initializing the
	 * static factory field.
	 * </p>
	 * 
	 * <p>
	 * Returns null if factory creation fails.
	 * </p>
	 * 
	 * @return a new IdentifierGeneratorFactory
	 */
	private static IdentifierGeneratorFactory createFactory() {
		try {
			return IdentifierGeneratorFactory.newInstance();
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a LongIdentifierGenerator to initialize LONG_IDENTIFIER_GENERATOR
	 * with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new LongIdentifierGenerator
	 * 
	 */
	private static LongIdentifierGenerator createLongIdentifierGenerator() {
		try {
			return factory.longGenerator(); // will toss NPE if factory is null
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a StringIdentifierGenerator to initialize
	 * STRING_NUMERIC_IDENTIFIER_GENERATOR with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new NumericGenerator
	 * 
	 */
	private static StringIdentifierGenerator createNumericIdentifierGenerator() {
		try {
			return factory.numericGenerator(); // will toss NPE if factory is
			// null
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a StringIdentifierGenerator to initialize
	 * STRING_ALPHANUMERIC_IDENTIFIER_GENERATOR with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new AlphaumericGenerator
	 * 
	 */
	private static StringIdentifierGenerator createAlphanumericGenerator() {
		try {
			return factory.alphanumericGenerator(); // will toss NPE if factory
			// is null
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a StringIdentifierGenerator to initialize
	 * STRING_SESSION_IDENTIFIER_GENERATOR with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new SessionIdGenerator
	 * 
	 */
	private static StringIdentifierGenerator createSessionIdGenerator() {
		try {
			return factory.sessionIdGenerator(); // will toss NPE if factory
			// is null
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a IdentifierGenerator that produces version one UUID to initialize
	 * UUID_VERSION_ONE_GENERATOR with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new IdentifierGenerator that produces version one UUIDs.
	 * 
	 */
	private static IdentifierGenerator<UUID> createUUIDVersionOneGenerator() {
		try {
			return factory.uuidVersionOneGenerator(); // will toss NPE if
			// factory is null
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * <p>
	 * Gets a IdentifierGenerator that produces version four UUID to initialize
	 * UUID_VERSION_FOUR_GENERATOR with.
	 * </p>
	 * 
	 * <p>
	 * Returns null if instance creation fails.
	 * </p>
	 * 
	 * @return a new IdentifierGenerator that produces version four UUIDs.
	 * 
	 */
	private static IdentifierGenerator<UUID> createUUIDVersionFourGenerator() {
		try {
			return factory.uuidVersionFourGenerator(); // will toss NPE if
			// factory is null
		} catch (Exception ex) {
			return null;
		}
	}

}
